#include "BlockQueue.hpp"
#include <unistd.h>
#include <vector>

//创建线程去交易生产者消费者队列，指定要生产消费的数量
class test {
private:
  //消费的run函数
  static void *producter(void *arg) {
    std::vector<void *> &info = *static_cast<std::vector<void *> *>(arg);
    test *mythis = static_cast<test *>(info[0]);
    std::string *name = static_cast<std::string *>(info[1]);
    //使用setname可以侧面面板显式看见线程
    pthread_setname_np(pthread_self(), name->c_str());

    // 1.队列满时消费者没有消费。
    //原因是push在test的实体_mtx锁内，满时在等待consumer的push，应该释放锁让consumer执锁
    // while (true) {
    //   pthread_mutex_lock(&mythis->_num_mtx);
    //   if (mythis->_actual_product_num == mythis->_required_product_num) {
    //     pthread_mutex_unlock(&mythis->_num_mtx);
    //     break;
    //   }

    //   mythis->_q.Push(mythis->_actual_product_num);
    //   std::cout << *name << " push:" << mythis->_actual_product_num
    //             << std::endl;
    //   ++mythis->_actual_product_num;
    //   pthread_mutex_unlock(&mythis->_num_mtx);

    //   usleep(1);
    // }

    // 2.错误逻辑
    //后++会使得多线程push一样的cur
    // while (true) {
    //   pthread_mutex_lock(&mythis->_num_mtx);
    //   int cur = mythis->_actual_product_num;
    //   if (cur == mythis->_required_product_num) {
    //     pthread_mutex_unlock(&mythis->_num_mtx);
    //     break;
    //   }

    //   pthread_mutex_unlock(&mythis->_num_mtx);
    //   mythis->_q.Push(cur);
    //   std::cout << *name << " push:" << cur << std::endl;

    //   pthread_mutex_lock(&mythis->_num_mtx);
    //   ++mythis->_actual_product_num;
    //   pthread_mutex_unlock(&mythis->_num_mtx);

    //   usleep(1);
    // }

    //正确
    while (true) {
      pthread_mutex_lock(&mythis->_num_mtx);
      int cur = mythis->_actual_product_num;
      if (cur == mythis->_required_product_num) {
        pthread_mutex_unlock(&mythis->_num_mtx);
        break;
      }
      //在同一锁内递增计数器，确保cur唯一
      mythis->_actual_product_num++;
      pthread_mutex_unlock(&mythis->_num_mtx);

      // 解锁后推送数据（cur已唯一，无重复）
      mythis->_q.Push(cur);
      pthread_mutex_lock(&mythis->_out_mtx);
      std::cout << *name << " push:" << cur << std::endl;
      pthread_mutex_unlock(&mythis->_out_mtx);
      sleep(1);
    }

    return nullptr;
  }

  //生产的run函数
  static void *consumer(void *arg) {
    std::vector<void *> &info = *static_cast<std::vector<void *> *>(arg);
    test *mythis = static_cast<test *>(info[0]);
    std::string *name = static_cast<std::string *>(info[1]);
    pthread_setname_np(pthread_self(), name->c_str());

    while (true) {
      pthread_mutex_lock(&mythis->_num_mtx);
      if (mythis->_actual_consume_num == mythis->_required_product_num) {
        pthread_mutex_unlock(&mythis->_num_mtx);
        break;
      }

      pthread_mutex_unlock(&mythis->_num_mtx);
      int val = 0;
      val = mythis->_q.Pop();

      pthread_mutex_lock(&mythis->_out_mtx);
      std::cout << "                          ";
      std::cout << *name << " pop:" << val << std::endl;
      pthread_mutex_unlock(&mythis->_out_mtx);

      pthread_mutex_lock(&mythis->_num_mtx);
      ++mythis->_actual_consume_num;
      pthread_mutex_unlock(&mythis->_num_mtx);

      sleep(1);
    }

    return nullptr;
  }

public:
  test(int cap, int product_num, int producter_num, int consumer_num)
      : _q(cap), _required_product_num(product_num),
        _producter_num(producter_num), _consumer_num(consumer_num){};
  ~test() {
    for (pthread_t p : _producter) {
      pthread_join(p, nullptr);
    }
    for (pthread_t c : _consumer) {
      pthread_join(c, nullptr);
    };
  };

  //交易所：创建消费者和生产者的线程调用run函数
  void transaction() {
    for (int i = 1; i <= _producter_num; i++) {
      pthread_t p;
      std::string *name = new std::string("producter" + std::to_string(i));
      std::vector<void *> *info =
          new std::vector<void *>{(void *)this, (void *)name};
      pthread_create(&p, nullptr, producter, info);
      _producter.push_back(p);
    }

    for (int i = 1; i <= _consumer_num; i++) {
      pthread_t c;
      std::string *name = new std::string("consumer" + std::to_string(i));
      std::vector<void *> *info =
          new std::vector<void *>{(void *)this, (void *)name};
      pthread_create(&c, nullptr, consumer, info);
      _consumer.push_back(c);
    }
  }

private:
  BlockQueue<int> _q;

  //保护下面3个数字的锁
  pthread_mutex_t _num_mtx = PTHREAD_MUTEX_INITIALIZER;
  int _required_product_num;
  int _actual_product_num = 0;
  int _actual_consume_num = 0;

  int _producter_num;
  int _consumer_num;
  std::vector<pthread_t> _producter;
  std::vector<pthread_t> _consumer;

  //保护输出的锁
  pthread_mutex_t _out_mtx = PTHREAD_MUTEX_INITIALIZER;
};